package DB.Evento;

import DB.DBManager;
import DB.EntityBase;
import Model.Evento;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

/**
 *
 * @author pgrabin
 */
public class ControllerEvento extends EntityBase<Evento> {

    DBManager db;
    Connection conn;
    private static ControllerEvento eControl;

    public static ControllerEvento getInstance() {
        if (eControl == null) {
            eControl = new ControllerEvento();
        }

        return eControl;
    }

    public ControllerEvento() {
        db = DBManager.getInstance();
        conn = db.getConn();
    }

    /**
     * Insere um novo EVENTO na base de dados.
     *
     * @param e o EVENTO a ser inserido.
     * @return o ID que o EVENTO recebeu, ou -1 se ocorreu algum erro.
     */
    public long insert(Evento e) {
        ResultSet generatedKeys = null;
        long idRetornado = 0;

        try {
            PreparedStatement ps = conn.prepareStatement("INSERT INTO eventos VALUES (null, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
            ps.setString(1, e.getNome());
            ps.setString(2, e.getDescricao());
            ps.setDouble(3, e.getValor());
            ps.setInt(4, e.getVagas());
            ps.setLong(5, e.getDataEvento().getTime());
            ps.setLong(6, e.getInicioInscricoes().getTime());
            ps.setLong(7, e.getFimInscricoes().getTime());
            ps.setString(8, e.getEndereco());
            ps.setString(9, e.getCidade());
            ps.setString(10, e.getEstado());
            ps.setString(11, e.getPais());
            ps.setString(12, e.getCep());

            int affectedRows = ps.executeUpdate();
            if (affectedRows == 0) {
                throw new SQLException("Creating event failed, no rows affected.");
            }
            generatedKeys = ps.getGeneratedKeys();
            if (generatedKeys.next()) {
                idRetornado = generatedKeys.getLong(1);
            } else {
                throw new SQLException("Creating event failed, no generated key obtained.");
            }
//            System.out.println("Evento inserido, recebeu o id: " + idRetornado);
        } catch (SQLException ex) {
            ex.printStackTrace(System.err);
        }

        return idRetornado;
    }

    /**
     * Retorna todos os eventos com data de hoje entre o periodo de inscrições
     *
     * @return ArrayList<Evento> contendo os eventos.
     */
    public ArrayList getOpenEventos() {
        ArrayList<Evento> eventos = new ArrayList<>();
        ResultSet rs;
        String query = "SELECT * FROM " + EventoTable.TABLE_NAME;

        try {
//            System.out.println(query);
            PreparedStatement ps = conn.prepareStatement(query);
            rs = ps.executeQuery();

            Calendar c = Calendar.getInstance();

            while (rs.next()) {
                Evento resultEvento = getFromResultSet(rs);
                System.out.println(resultEvento.getNome());

                if (resultEvento.getInicioInscricoes().before(c.getTime()) && resultEvento.getFimInscricoes().after(c.getTime())) {
                    System.out.println(resultEvento.getNome());
                    eventos.add(resultEvento);
                }
            }
        } catch (SQLException e) {
            e.printStackTrace(System.err);
        }

        return eventos;
    }

    public int getVagasById(long idEvento) {
        int retorno = 0;
        ResultSet rs;

        String query = "SELECT " + EventoTable.COLUMN_VAGAS
                + " FROM " + EventoTable.TABLE_NAME
                + " WHERE " + EventoTable.COLUMN_ID + " = ? ";

//        System.out.println(query);
        try {
            PreparedStatement ps = conn.prepareStatement(query);
            ps.setLong(1, idEvento);

            rs = ps.executeQuery();

            if (rs.next()) {
                retorno = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace(System.err);
        }

        return retorno;
    }

    /**
     * Retorna todos os registros da tabela.
     *
     * @return Um arrayList<Evento> contendo todos os registros.
     */
    @Override
    public ArrayList getAll() {
        ArrayList<Evento> eventos = new ArrayList<>();
        ResultSet rs;

        try {
            PreparedStatement ps = conn.prepareStatement("SELECT * FROM " + EventoTable.TABLE_NAME);
            rs = ps.executeQuery();

            while (rs.next()) {
                Evento resultEvento = getFromResultSet(rs);
                eventos.add(resultEvento);
            }
        } catch (SQLException e) {
            e.printStackTrace(System.err);
        }

        return eventos;
    }

    /**
     * Converte o resultSet do banco em um Evento
     *
     * @param rs o resultSet
     * @return e Evento retornado
     */
    @Override
    public Evento getFromResultSet(ResultSet rs) {
        Evento e = null;

        try {
            int id = rs.getInt(1); //EventoTable.COLUMN_ID);
            String nome = rs.getString(EventoTable.COLUMN_NOME);
            String descricao = rs.getString(EventoTable.COLUMN_DESCRICAO);
            double valor = rs.getDouble(EventoTable.COLUMN_VALOR);
            int vagas = rs.getInt(EventoTable.COLUMN_VAGAS);
            long dataEvento = rs.getLong(EventoTable.COLUMN_DATAEVENTO);
            long inicioInscricoes = rs.getLong(EventoTable.COLUMN_INICIOINSCRICOES);
            long fimInscricoes = rs.getLong(EventoTable.COLUMN_FIMINSCRICOES);
            String endereco = rs.getString(EventoTable.COLUMN_ENDERECO);
            String cidade = rs.getString(EventoTable.COLUMN_CIDADE);
            String estado = rs.getString(EventoTable.COLUMN_ESTADO);
            String pais = rs.getString(EventoTable.COLUMN_PAIS);
            String cep = rs.getString(EventoTable.COLUMN_CEP);

            e = new Evento(id, nome, descricao, valor, vagas, dataEvento, inicioInscricoes, fimInscricoes, endereco, cidade, estado, pais, cep);
//            System.out.println(   "eventoGetFromResultSet retornando: " + e.toString());
        } catch (SQLException ex) {
            ex.printStackTrace(System.err);
        }

        return e;
    }

    /**
     * Retorna o EVENTO cujo ID é igual ao ID informado, Ou null caso não
     * encontre algum EVENTO com aquele ID.
     *
     * @param id ID do EVENTO que será retornado.
     * @return Retorna o EVENTO com o ID informado
     */
    @Override
    public Evento getByID(long id) {
        ResultSet rs;
        Evento e = null;

        try {
            PreparedStatement ps = conn.prepareStatement("SELECT * FROM " + EventoTable.TABLE_NAME + " WHERE ID = ?");
            ps.setLong(1, id);

            rs = ps.executeQuery();

            if (rs.next()) {
                e = getFromResultSet(rs);
            } else {
                throw new SQLException("Evento não encontrada.");
            }
        } catch (SQLException ex) {
            ex.printStackTrace(System.err);
        }

        return e;
    }

    /**
     * Deleta da base de dados o registro com o ID informado
     *
     * @param id O ID do USUARIO que deve ser deletado.
     * @return Quantidade de linhas afetadas.
     */
    @Override
    public int delete(long id) {
        int resultadoDelete = 0;

        try {
            PreparedStatement ps = conn.prepareStatement("DELETE FROM " + EventoTable.TABLE_NAME + " WHERE " + EventoTable.COLUMN_ID + " = ?");
            ps.setLong(1, id);

            resultadoDelete = ps.executeUpdate();
            if (resultadoDelete == 0) {
                throw new SQLException("No record found for deletion!");
            } else if (resultadoDelete > 1) {
                throw new SQLException("More than one row deleted!");
            } else {
                System.out.println("Evento código " + id + " deletado!");
            }

        } catch (SQLException e) {
            e.printStackTrace(System.err);
        }

        return resultadoDelete;
    }

    /**
     * Retorna todos os eventos com acontecendo hoje.
     *
     * @return ArrayList<Evento> contendo os eventos.
     */
    public ArrayList getTodayEvents() {
        ArrayList<Evento> eventos = new ArrayList<>();
        ResultSet rs;

        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);

        Date hoje = c.getTime();
        Date ontem = new Date(hoje.getTime() - 86400000);
        Date amanha = new Date(hoje.getTime() + 86400000);

//        System.out.println("Testando eventos acontecendo hoje...");
//        System.out.println("Hoje é " + hoje);
//        System.out.println("Ontem: " + ontem);
//        System.out.println("Amanha: " + amanha);
        String query = "SELECT * FROM " + EventoTable.TABLE_NAME + " "
                + "WHERE " + EventoTable.COLUMN_DATAEVENTO + " > ? AND " + EventoTable.COLUMN_DATAEVENTO + " < ?";

//        System.out.println(query);
        try {
            PreparedStatement ps = conn.prepareStatement(query);
            ps.setLong(1, ontem.getTime());
            ps.setLong(2, amanha.getTime());

            rs = ps.executeQuery();

            while (rs.next()) {
                Evento resultTest = getFromResultSet(rs);
                eventos.add(resultTest);
            }
        } catch (SQLException e) {
            e.printStackTrace(System.err);
            System.exit(0);
        }

        return eventos;
    }

    /**
     * Atualiza o registro na base de dados do usuario recebido como parametro,
     * tomando como base o ID.
     *
     * @param e O EVENTO que deve ter suas informações atualizadas.
     * @return Quantidade de linhas afetadas.
     */
    @Override
    public long update(Evento e) {
        ResultSet generatedKeys = null;
        long affectedRows = 0;

        try {
            PreparedStatement ps = conn.prepareStatement("UPDATE " + EventoTable.TABLE_NAME
                    + " SET nome = ?,"
                    + " descricao = ?,"
                    + " valor = ?,"
                    + " vagas = ?,"
                    + " dataEvento = ?,"
                    + " inicioInscricoes = ?,"
                    + " fimInscricoes = ?,"
                    + " endereco = ?,"
                    + " cidade = ?,"
                    + " estado = ?,"
                    + " pais = ?,"
                    + " cep = ?"
                    + " WHERE id = ?", Statement.RETURN_GENERATED_KEYS);

            ps.setString(1, e.getNome());
            ps.setString(2, e.getDescricao());
            ps.setDouble(3, e.getValor());
            ps.setInt(4, e.getVagas());
            ps.setLong(5, e.getDataEvento().getTime());
            ps.setLong(6, e.getInicioInscricoes().getTime());
            ps.setLong(7, e.getFimInscricoes().getTime());
            ps.setString(8, e.getEndereco());
            ps.setString(9, e.getCidade());
            ps.setString(10, e.getEstado());
            ps.setString(11, e.getPais());
            ps.setString(12, e.getCep());
            ps.setLong(13, e.getId());

//            System.out.println(e.getId() + " - " + e.getNome());
            affectedRows = ps.executeUpdate();
            if (affectedRows == 0) {
                throw new SQLException("Update failed, no rows affected");
            } else if (affectedRows > 1) {
//                        throw new SQLException("More than one rows updated");
            }
        } catch (SQLException ex) {
            ex.printStackTrace(System.err);
        }

        return affectedRows;
    }

    /**
     * Retorna a quantidade de registros na tabela.
     *
     * @return a quantidade de registros;
     */
    @Override
    public int getRowsCount() {
        return db.getTableCount(EventoTable.TABLE_NAME);
    }

    /**
     * Adiciona alguns registros padrão na tabela, para testes e demonstrações
     * de usabilidade.
     */
    public void standardEventos() {
        Evento a, b, c, d, e;

        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.HOUR_OF_DAY, 0);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);

        Date date = ca.getTime();

        ca.add(Calendar.DAY_OF_MONTH, -1);
        Date antes = ca.getTime();

        ca.add(Calendar.DAY_OF_MONTH, 2);
        Date depois = ca.getTime();

        a = new Evento("Viagem", "Descrição evento 1 blablablablalbalba", 5.25, 50, date.getTime(), antes.getTime(), depois.getTime(), "Endereço", "Cidade", "Estado", "Pais", "CEP");
        b = new Evento("Final Mundial Interclubes", "Descrição evento 2 blablablablalbalba", 500, 50, date.getTime(), antes.getTime(), depois.getTime(), "Endereço", "Cidade", "Estado", "Pais", "CEP");
        c = new Evento("Apresentação DEV III", "Descrição evento 3 blablablablalbalba", 0, 50, date.getTime(), antes.getTime(), depois.getTime(), "Endereço", "Cidade", "Estado", "Pais", "CEP");
        d = new Evento("Entrevista SAP", "Descrição evento 4 blablablablalbalba", 0, 1, date.getTime(), antes.getTime(), depois.getTime(), "Endereço", "Cidade", "Estado", "Pais", "CEP");
        e = new Evento("Rock show", "Descrição evento 5 blablablablalbalba", 250, 50, date.getTime(), antes.getTime(), depois.getTime(), "Endereço", "Cidade", "Estado", "Pais", "CEP");

        long aa = insert(a);
        long bb = insert(b);
        long cc = insert(c);
        long dd = insert(d);
        long ee = insert(e);

        System.out.println("Eventos padrão inseridos, ids: " + aa + " " + bb + " " + cc + " " + dd + " " + ee);
    }
    
    public void getDatas() {
        ArrayList<Evento> eventos = getAll();
        
        for(Evento e : eventos) {
            System.out.println(e.getNome() + "\t - " + e.getDataEvento() + "\t - " + e.getInicioInscricoes() + "\t - " + e.getFimInscricoes());
        }
    }

    public static void main(String args[]) {
        ControllerEvento ce = getInstance();
        Evento e = ce.getByID(1);
        
        System.out.println(e.toString());
        
        ce.insert(e);
        
        e.setDataEvento(2323);
        e.setInicioInscricoes(2323);
        e.setFimInscricoes(2323);
        
        ce.update(e);
        
        
        
        
        
        
        
        
//        Calendar ca = Calendar.getInstance();
//        ca.set(Calendar.HOUR_OF_DAY, 0);
//        ca.set(Calendar.MINUTE, 0);
//        ca.set(Calendar.SECOND, 0);
//
//        Date hoje = ca.getTime();
//
//        ca.add(Calendar.DAY_OF_MONTH, 1);
//        Date antes = ca.getTime();
//
//        ca.add(Calendar.DAY_OF_MONTH, -2);
//        Date depois = ca.getTime();
//
//        System.out.println(hoje);
//        System.out.println(antes);
//        System.out.println(depois);
        
        
//        ce.getDatas();
    }
}